1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 
12 module hip.api.internal;
13 import hip.api;
14 import hip.util.lifetime;
15 
16 ///Used for creating a function which will generate an overload to call a function pointer
17 struct Overload
18 {
19 	string targetName;
20 }
21 
22 version(WebAssembly) version = ErrorOnLoadSymbol;
23 version(PSVita) version = ErrorOnLoadSymbol;
24 
25 version(ScriptAPI) version = LoadFunctionPointers;
26 
27 
28 version(LoadFunctionPointers)
29 {
30 	__gshared void* _dll;
31 	void initializeHip()
32 	{
33 		version(ErrorOnLoadSymbol)
34 		{
35 			assert(false, "Cannot load symbols in this version.");
36 		}
37 		else
38 		{
39 			version(Windows){_dll = GetModuleHandle(null);}
40 			else
41 			{
42 				import core.sys.posix.dlfcn:dlopen, RTLD_NOW;
43 				_dll = dlopen(null, RTLD_NOW);
44 			}
45 			import core.stdc.stdio;
46 			if(_dll == null)
47 				printf("Could not load GetModuleHandle(null)\n");
48 			hipDestroy = cast(typeof(hipDestroy))_loadSymbol(_dll, "hipDestroy");
49 			if(hipDestroy == null)
50 				printf("Fatal error: could not load hipDestroy\n");
51 		}
52 	}
53 }
54 version(Windows)
55 {
56 	@nogc nothrow extern(Windows)
57 	{
58 		void* GetModuleHandleW(const(wchar)* str);
59 		void* GetProcAddress(void* mod, const(char)* func);
60 		void* FreeLibrary(void* lib);
61 		uint GetLastError();
62 	}
63 	alias GetModuleHandle = GetModuleHandleW;
64 	alias _loadSymbol = GetProcAddress;
65 }
66 
67 version(Posix)
68 {
69 	import core.sys.posix.dlfcn:dlsym;
70 	alias _loadSymbol = dlsym;
71 }
72 enum bool isFunctionPointer(alias T) = is(typeof(*T) == function);
73 
74 /**
75 *	Prefer using that function instead of loadSymbol, as compile
76 *	time sequences reduced the binary size in almost 100kb.
77 *
78 *	The problem is not yet solved, but it is a lot better than doing several
79 *	template instantiations
80 */
81 void loadSymbols(Ts...)()
82 {
83 	static foreach(s; Ts)
84 		s = cast(typeof(s))_loadSymbol(_dll, s.stringof);
85 }
86 
87 /**
88 *	This function will load all function pointers defined in the module passed.
89 */
90 void loadModuleFunctionPointers(alias targetModule, string exportedClass = "")()
91 {
92 	string prefix = "";
93 	string importedFunctionName;
94 	static if(exportedClass != "")
95 		prefix = exportedClass~"_";
96 	static foreach(member; __traits(allMembers, targetModule))
97 	{{
98 		alias f = __traits(getMember, targetModule, member);
99 		static if(isFunctionPointer!(f))
100 		{
101 			importedFunctionName = prefix~member~'\0';
102 			if(f is null)
103 			{
104 				f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr);
105 				if(f is null)
106 				{
107 					import core.stdc.stdio;
108 					printf(f.stringof~" wasn't able to load (tried with %s)\n", importedFunctionName.ptr);
109 				}
110 			}
111 		}
112 	}}
113 }
114 
115 
116 string generateFunctionDefinitionFromFunctionPointer(alias funcPointerSymbol, string name)()
117 {
118 	assert(__ctfe);
119 
120 	import std.traits;
121 	string params;
122 	string identifiers;
123 
124 	bool isFirst = true;
125 	alias storage = ParameterStorageClassTuple!funcPointerSymbol;
126 	static foreach(i, p; Parameters!funcPointerSymbol)
127 	{
128 		if(!isFirst)
129 		{
130 			params~= ",";
131 			identifiers~= ",";
132 		}
133 		else
134 			isFirst = false;
135 		if(storage[i] != ParameterStorageClass.none)
136 			params~= storage[i].stringof["ParameterStorageClass.".length..$-1] ~" "; //Remove enum namespace and the "_"
137 		params~= p.stringof ~ " _"~i.stringof;
138 		identifiers~= "_"~i.stringof;
139 	}
140 
141 	return (ReturnType!funcPointerSymbol).stringof ~ " "~ name ~ "("~params 
142 	~"){return "~ funcPointerSymbol.stringof ~ "("~identifiers ~ ");}";
143 
144 }
145 
146 mixin template OverloadsForFunctionPointers(alias targetModule)
147 {
148 	import std.traits;
149 	static foreach(symbol; getSymbolsByUDA!(targetModule, Overload))
150 	{
151 		pragma(msg, generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName));
152 		mixin(generateFunctionDefinitionFromFunctionPointer!(symbol, getUDAs!(symbol, Overload)[0].targetName));
153 	}
154 }
155 
156 mixin template ExpandClassFunctionPointers(alias targetClass)
157 {
158 	import hip.api.internal: isFunctionPointer;
159 
160 	static foreach(mem; __traits(allMembers, targetClass))
161 	{
162 		static if(isFunctionPointer!(__traits(getMember, targetClass, mem)))
163 		{
164 			mixin(__traits(getVisibility, __traits(getMember, targetClass, mem)), " alias ", mem, " = ", __traits(identifier, targetClass), ".", mem,";");
165 		}
166 	}
167 }
168 template Flag(string f)
169 {
170 	enum Flag : bool
171 	{
172 		No = false,
173 		Yes = true
174 	}
175 }
176 
177 alias UseExportedClass = Flag!"UseExportedClass";
178 
179 void loadClassFunctionPointers(alias targetClass, 
180 	UseExportedClass useExported = UseExportedClass.No, 
181 	string exportedClass = "")
182 ()
183 {
184 	string prefix = "";
185 	string importedFunctionName;
186 
187 	version(ErrorOnLoadSymbol)
188 	{
189 		assert(false, "Cannot load symbols in this version.");
190 	}
191 	else
192 	{
193 		string nExportedClass = exportedClass;
194 		static if(useExported)
195 		{
196 			static if(exportedClass == "")
197 				nExportedClass = targetClass.stringof;
198 			prefix = nExportedClass~"_";
199 		}
200 		static foreach(member; __traits(allMembers, targetClass))
201 		{{
202 			alias f = __traits(getMember, targetClass, member);
203 			static if(isFunctionPointer!(f))
204 			{
205 				importedFunctionName = prefix~member~'\0';
206 				f = cast(typeof(f))_loadSymbol(_dll, importedFunctionName.ptr);
207 				if(f is null)
208 				{
209 					import core.stdc.stdio;
210 					printf(f.stringof ~ " wasn't able to load (tried with %s)\n", importedFunctionName.ptr);
211 
212 					f = cast(typeof(f))()
213 					{
214 						printf("Symbol '"~member~"' wasn't able to load.\n"~
215 						"If on that is working on LDC, please check for exportd."~
216 						"referenceExported to see if that function referenced. Check https://github.com/dlang/dmd/issues/17582 for more information. \n\n\t"~
217 						"Hipreme Engine will exit.\n"
218 						);
219 						assert(false);
220 					};
221 				}
222 			}
223 		}}
224 	}
225 }
226 
227 template loadSymbolsFromExportD(string exportedClass, Ts...)
228 {
229 	version(ErrorOnLoadSymbol)
230 	{
231 		enum impl = "";
232 	}
233 	else
234 	{
235 		enum impl = ()
236 		{
237 			assert(__ctfe);
238 
239 			enum e = '"'~exportedClass~"_\"";
240 			string ret;
241 			static foreach(i, s; Ts)
242 			{
243 				ret~= s.stringof ~"= cast(typeof("~s.stringof~ " ))_loadSymbol(_dll, ("~e~"~\""~s.stringof~"\\0\").ptr);";
244 				if(s.stringof is null)
245 				{
246 					import core.stdc.stdio;
247 					printf("Could not load "~s.stringof~" (tried with "~ e~s.stringof~")\n");
248 				}
249 			}
250 			return ret;
251 		}();
252 	}
253 
254 	enum loadSymbolsFromExportD = impl;
255 }